package 并发.多线程;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 创建线程的方式：
 * 继承Thread并重写run方法；
 * 实现Runnable接口并将其传递给Thread的构造器
 * 建议使用Runnable接口：
 * 在面向对象设计中，有一条约定俗成的规则，组合优于继承（Prefer composition over inheritance），
 * 如果没有特别的目的需要重写父类方法，尽量不要使用继承。在Java中所有的类都只能是单继承，一旦继承Thread之后将不能继承其他类，严重影响类的扩展和灵活性。
 * 另外，实现Runnable接口也可以与后面的更高级的并发工具结合使用。
 * @author 翟晓龙
 * @date 2022/4/20
 */
public class ThreadTest {

    public static Integer num = 10000;

    public void newThread(){

        Thread t1 = new Thread(() -> {
            while (num > 0){
                System.out.println("t1:" + num--);
            }
        });

        Thread t2 = new Thread(){
            @Override
            public void run() {
                while (num > 0){
                    System.out.println("t2:" + num--);
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (num > 0){
                    System.out.println("t3:" + num--);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        t1.start();;
        t2.start();
        t3.start();
    }

    public static void main(String[] args) throws InterruptedException {
//        turnRun();
        Thread exThread = new Thread(()-> {
            throw new RuntimeException("子线程异常");
        });
        Thread.setDefaultUncaughtExceptionHandler(new MyThreadExceptionHandler());
        try {
            exThread.start();
        }catch (Exception ex){
            System.out.println("cache ex" + ex.getMessage());
        }

    }

    static class MyThreadExceptionHandler implements Thread.UncaughtExceptionHandler{

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println("出错了！线程名：" + t.getName() + "，线程ID：" + t.getId() + "，错误信息：" + e.getMessage());
        }
    }


    /**
     * 两个线程交替打印
     */
    public static void turnRun() throws InterruptedException {

        Thread t1 = new Thread(()->{
            while (count < 101){
                synchronized (lock){
                    if (count % 2 != 0){
                        System.out.println("t1:" + count ++ );
                        lock.notify();
                    }
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Thread t2 = new Thread(()->{
            while (count < 101){
                synchronized (lock){
                    if (count % 2 == 0){
                        System.out.println("t2:" + count ++ );
                        lock.notify();
                    }
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        t1.start();t2.start();


//        new Thread(new TurningRunner(),"奇数线程").start();
//        new Thread(new TurningRunner(),"偶数线程").start();

    }

    static int count = 1;
    static Object lock = new Object();

    static class TurningRunner implements Runnable{

        @Override
        public void run() {
            while (count < 101){
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName() + ":" + count ++ );
                    lock.notify();
                    if (count < 101){
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }
    }
}
